package org.raymond.icloud.common.core.security.model;

import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.raymond.icloud.common.core.constants.CacheConstants;
import org.raymond.icloud.common.core.constants.ErrorCode;
import org.raymond.icloud.common.core.exception.BaseException;
import org.raymond.icloud.common.core.security.Authentication;
import org.raymond.icloud.common.core.security.Certification;
import org.raymond.icloud.common.core.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

public abstract class UsernamepasswordAuthentication implements Authentication {
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public boolean authenticate(Certification certification) throws BaseException {
        Certification another = this.findByCertification(certification);
        if(another == null){
            throw new BaseException(ErrorCode.UNAUTHORIZED, "certification not exists");
        }
        if(certification.authenticate(another)){
            BeanUtils.copyProperties(another, certification);
            return true;
        }
        return false;
    }

    public Certification findByCertification(Certification certification) {
        UsernamepasswordCertification input = (UsernamepasswordCertification) certification;
        UsernamepasswordCertification anOther = findByUsername(input.getUsername());
        if(anOther==null) return null;

        Object tokenObj = redisUtil.get(CacheConstants.PREFIX_TOKEN+anOther.getId());
        UsernamepasswordCertification cert = null;
        if(Objects.nonNull(tokenObj)){
            Object cachedObj = redisUtil.get(CacheConstants.PREFIX_CERT+tokenObj);
            if(cachedObj instanceof UsernamepasswordCertification) {
                cert = (UsernamepasswordCertification) cachedObj;
                // todo 缓存展期
            }
        }
        if(cert!=null){
            return cert;
        }
        String token = createToken();
        anOther.setCertification(token);
        anOther.setExpire(CacheConstants.expireTime(CacheConstants.CERT_EXPIRE_S));
        redisUtil.set(CacheConstants.PREFIX_TOKEN+anOther.getId(), token, CacheConstants.expireTime(CacheConstants.TOKEN_EXPIRE_S));
        redisUtil.set(CacheConstants.PREFIX_CERT+token, anOther, anOther.getExpire());
        cert = anOther;
        return cert;
    }

    public String createToken(){
        return UUID.randomUUID().toString();
    }

    protected abstract UsernamepasswordCertification findByUsername(String username);
}
